package com.warthur.spring.demo.framework.filter;

import com.warthur.spring.demo.common.JwtTokenUtils;
import com.warthur.spring.demo.pojo.domain.JwtAuthenticationToken;
import com.warthur.spring.demo.pojo.domain.User;
import com.warthur.spring.demo.service.UserDetailsService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;

/**
 * @author warthur
 * @date 2019/10/06
 */
public class TokenAuthenticationProvider implements AuthenticationProvider {

    private UserDetailsService userDetailsService;

    public TokenAuthenticationProvider(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        if (authentication.isAuthenticated()) {
            return authentication;
        }

        // 从 TokenAuthentication 中获取 token
        String token = authentication.getCredentials().toString();
        if (StringUtils.isEmpty(token)) {
            throw new BadCredentialsException("Bad credentials");
        }
        User user;
        try {
            user = JwtTokenUtils.getTokenUser(token, User.class);
            if (user == null) {
                return authentication;
            }

            user = userDetailsService.loadUserByUsername(user.getUsername());
            if (user == null) {
                return authentication;
            }

            if (!JwtTokenUtils.validateToken(token, user)) {
                throw new BadCredentialsException("Bad credentials");
            }
        } catch (Exception e) {
            throw new BadCredentialsException("Bad credentials");
        }

        Authentication auth = new PreAuthenticatedAuthenticationToken(user, token, user.getAuthorities());
        auth.setAuthenticated(true);

        return auth;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return JwtAuthenticationToken.class.isAssignableFrom(authentication);
    }
}
